<script setup lang="ts">
import bigjs from "big.js";
import { ref, watch } from "vue";
import { isNumber, gte, lte, isUndefined } from "lodash-es";

import Icon from "@/components/Icon.vue";

import { isNilStrong } from "@/utils/tool";
import { ElInput } from "element-plus";

// 加
function plus(a: number, b: number) {
  // return bignumber(a).plus(b).toNumber();
  return bigjs(a).plus(b).toNumber();
}

// 减
function minus(a: number, b: number) {
  return bigjs(a).minus(b).toNumber();
}

// 乘
function times(a: number, b: number) {
  return bigjs(a).times(b).toNumber();
}

// 除
function div(a: number, b: number) {
  return bigjs(a).div(b).toNumber();
}

const props = withDefaults(
  defineProps<{
    modelValue: string | number | undefined;
    placeholder?: string;
    disabled?: boolean;
    precision?: number;
    step?: number;
    min?: number;
    max?: number;
    initialValue?: number;
    prefix?: string;
    hiddenAction?: string;
    baseNum?: number;

    align?: "left" | "center" | "right";

    isString?: boolean;
  }>(),
  {
    baseNum: 1,
  }
);

const emits = defineEmits(["update:modelValue"]);

const toString = (val) => (props.isString ? val.toString() : val);

let isInput = false;

// 过滤特殊字符
function clearNumberSpecialChar(val: string) {
  isInput = true;
  // 先把非数字的都替换掉，除了数字'.'和'-'
  val = val.replace(/[^\d.-]/g, "");

  // 除去非首位-
  val = val.replace(/^\-/, "$").replace(/\-/g, "").replace("$", "-");

  // 保证.只出现一次，而不能出现两次以上
  val = val.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");

  // emits("update:modelValue", val);
  inputValue.value = val;
}

//
function eventStep(type?: "subtract" | "plus") {
  let { step = 1, min, max, initialValue } = props;

  const needValidate = isInput;
  isInput = false;

  let modelValue = inputValue.value;

  if (
    (!type && isNilStrong(modelValue)) || // 失去焦点
    (!type && !needValidate && modelValue == initialValue) ||
    /\-$/.test(modelValue + "")
  ) {
    inputValue.value = initialValue ?? "";
    return;
  }

  let value: number | string = Number(modelValue || 0);

  if (type) {
    // 避免精度丢失
    value = type == "subtract" ? minus(value, step) : plus(value, step);
  }

  if (isNumber(props.precision)) {
    value = value.toFixed(props.precision);
  }

  if (!isUndefined(min) && +value < min) {
    value = min;
  } else if (!isUndefined(max) && +value > max) {
    value = max;
  }

  inputValue.value = value + "";
  // emits("update:modelValue", +value);
}

// 输入值
const inputValue = ref();
watch(inputValue, (val) => {
  const _val = Number(val);
  if (!isNaN(_val)) {
    emits("update:modelValue", toString(times(Number(val), props.baseNum)));
  }
});

watch(
  () => props.modelValue,
  (val) => {
    if (
      inputValue.value === "" ||
      inputValue.value === undefined ||
      val !== times(inputValue.value || 0, props.baseNum)
    ) {
      inputValue.value = val ? div(Number(val), props.baseNum) : val;
    }
  },
  {
    immediate: true,
  }
);
</script>
<template>
  <ElInput
    v-model="inputValue"
    :placeholder="placeholder"
    :disabled="disabled"
    @input="clearNumberSpecialChar"
    @blur="eventStep()"
    class="cus-input-number el-input-number is-controls-right w-150px"
    :class="{
      'text-left': align == 'left',
      'text-center': !align || align == 'center',
      'text-right': align == 'right',
    }"
  >
    <template #prefix>{{ prefix }}</template>

    <template #append v-if="!hiddenAction">
      <span
        class="el-input-number__increase"
        :class="{ 'is-disabled': disabled || gte(modelValue, Number(max)) }"
        @click="eventStep('plus')"
      >
        <Icon name="ArrowUp" />
      </span>
      <span
        class="el-input-number__decrease"
        :class="{ 'is-disabled': disabled || lte(modelValue, Number(min)) }"
        @click="eventStep('subtract')"
      >
        <Icon name="ArrowDown" />
      </span>
    </template>
  </ElInput>
</template>

<style lang="less">
.cus-input-number {
  .el-input__wrapper {
    //   // border-radius: 0 4px 4px 0;

    padding-left: 11px !important;
  }

  .el-input-group__append {
    padding: 0 !important;
  }

  .el-input-group__prepend {
    margin-right: -1px;
  }

  .el-input__inner {
    text-align: inherit;
  }
}

.el-form-item.is-error {
  .el-input-group__prepend {
    box-shadow: 0 0 0 1px var(--el-color-danger) inset;
  }
}
</style>
